package com.blog.blog.controller;

import com.blog.blog.common.ApiBaseResponse;
import com.blog.blog.common.PageResponse;
import com.blog.blog.dto.ArticleListQueryDTO;
import com.blog.blog.service.ArticleService;
import com.blog.blog.vo.ArticleArchiveItemVO;
import com.blog.blog.vo.ArticleListItemVO;
import com.blog.blog.config.SiteProperties;
import com.blog.blog.service.CaptchaService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.blog.blog.util.annotations.RateLimit;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import java.util.List;
import java.util.Map;

@Tag(name = "文章管理", description = "博客文章相关接口")
@com.blog.blog.util.annotations.OpLog(module = "Article")
@RestController
@RequestMapping("/api/articles")
public class ArticleController {

    private final ArticleService articleService;
    private final com.blog.blog.service.LikeService likeService;
    private final SiteProperties siteProperties;
    private final CaptchaService captchaService;

    public ArticleController(ArticleService articleService, com.blog.blog.service.LikeService likeService, SiteProperties siteProperties, CaptchaService captchaService) {
        this.articleService = articleService;
        this.likeService = likeService;
        this.siteProperties = siteProperties;
        this.captchaService = captchaService;
    }

    @Operation(summary = "获取文章列表", description = "分页查询文章列表，支持关键词搜索、分类筛选、排序等")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "查询成功"),
        @ApiResponse(responseCode = "400", description = "参数错误")
    })
    @GetMapping
    public ApiBaseResponse<PageResponse<ArticleListItemVO>> list(
            @Parameter(description = "查询参数") @Validated ArticleListQueryDTO queryDTO) {
        return ApiBaseResponse.success(articleService.pageArticles(queryDTO));
    }

    // RSS 简易输出（最近 N 篇），生产可改为 Atom 或更完整的 RSS 规范
    @GetMapping(value = "/rss", produces = "application/rss+xml;charset=UTF-8")
    public String rss(@RequestParam(required = false) Integer limit) {
        int size = (limit == null || limit <= 0) ? 20 : Math.min(limit, 100);
        // 直接通过 service 层分页取近 N 条
        com.blog.blog.dto.ArticleListQueryDTO q = new com.blog.blog.dto.ArticleListQueryDTO();
        q.setStatus(1);
        q.setPageNo(1);
        q.setPageSize(size);
        java.util.List<ArticleListItemVO> items = articleService.pageArticles(q).getRecords();
        String base = siteProperties.getBaseUrl() != null ? siteProperties.getBaseUrl().replaceAll("/$", "") : "";
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        sb.append("<rss version=\"2.0\"><channel>\n");
        sb.append("<title>Blog RSS</title>\n");
        sb.append("<link>").append(base).append("/").append("</link>\n");
        sb.append("<description>Recent posts</description>\n");
        for (ArticleListItemVO it : items) {
            sb.append("<item>");
            sb.append("<title>").append(escapeXml(it.getTitle())).append("</title>");
            sb.append("<link>").append(base).append("/article/").append(it.getId()).append("</link>");
            sb.append("<description>").append(escapeXml(it.getSummary())).append("</description>");
            sb.append("<pubDate>").append(it.getCreateTime() == null ? "" : it.getCreateTime().toString().replace('T',' ')).append("</pubDate>");
            sb.append("</item>\n");
        }
        sb.append("</channel></rss>");
        return sb.toString();
    }

    private String escapeXml(String s) {
        if (s == null) return "";
        return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;");
    }

    @GetMapping("/{id}")
    public ApiBaseResponse<?> detail(@PathVariable Long id) {
        return ApiBaseResponse.success(articleService.getArticleDetail(id));
    }

    @PostMapping("/{id}/like")
    @RateLimit(key = "article:like", rate = 5, interval = 10)
    public ApiBaseResponse<?> like(@PathVariable Long id) {
        articleService.likeArticle(id);
        return ApiBaseResponse.success(true);
    }

    // 评论列表（公开）- 平铺或树形分页
    @GetMapping("/{id}/comments")
    public ApiBaseResponse<?> listComments(@PathVariable Long id, Integer pageNo, Integer pageSize, Boolean tree) {
        if (Boolean.TRUE.equals(tree)) {
            return ApiBaseResponse.success(articleService.pageCommentTrees(id, pageNo, pageSize));
        }
        return ApiBaseResponse.success(articleService.listComments(id));
    }

    // 发表评论（公开，基础防刷应在Nginx/网关或限流处处理）
    @PostMapping("/{id}/comments")
    @RateLimit(key = "article:comment", rate = 3, interval = 30)
    public ApiBaseResponse<?> addComment(@PathVariable Long id, @Validated @RequestBody com.blog.blog.dto.CreateCommentDTO dto) {
        dto.setArticleId(id);
        // 验证码校验（简单问答）
        if (!captchaService.validate(dto.getCaptchaToken(), dto.getCaptchaAnswer(), true)) {
            return ApiBaseResponse.error(400, "请先完成验证码校验");
        }
        articleService.addComment(dto);
        return ApiBaseResponse.success(true);
    }
    // 评论点赞（公开）
    @PostMapping("/comments/{commentId}/like")
    @RateLimit(key = "comment:like", rate = 10, interval = 30)
    public ApiBaseResponse<Long> likeComment(@PathVariable Long commentId, org.springframework.web.context.request.WebRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isBlank()) ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.isBlank()) ip = "";
        String ua = request.getHeader("User-Agent");
        String actorKey = (ip == null ? "" : ip) + "|" + (ua == null ? "" : ua);
        boolean first = likeService.registerCommentLike(commentId, actorKey, 7 * 24 * 3600);
        long v = first ? likeService.incrementCommentLike(commentId) : likeService.getCommentLikeCount(commentId);
        return ApiBaseResponse.success(v);
    }

    // 批量查询评论点赞数（公开）
    @GetMapping("/comments/likes")
    public ApiBaseResponse<Map<Long, Long>> commentLikes(@RequestParam java.util.List<Long> ids) {
        return ApiBaseResponse.success(likeService.getCommentLikes(ids));
    }

    // 分类/标签（公开）
    @GetMapping("/categories")
    public ApiBaseResponse<?> categories() {
        return ApiBaseResponse.success(articleService.listCategories());
    }

    @GetMapping("/tags")
    public ApiBaseResponse<?> tags() {
        return ApiBaseResponse.success(articleService.listTags());
    }

    // 相关文章（公开）
    @GetMapping("/{id}/related")
    public ApiBaseResponse<List<ArticleListItemVO>> related(@PathVariable Long id, @RequestParam(required = false) Integer limit) {
        return ApiBaseResponse.success(articleService.listRelatedArticles(id, limit));
    }

    // 热门文章（公开）
    @GetMapping("/hot")
    public ApiBaseResponse<List<ArticleListItemVO>> hot(@RequestParam(required = false) Integer limit,
                                                        @RequestParam(required = false) Long categoryId,
                                                        @RequestParam(required = false) Long tagId,
                                                        @RequestParam(required = false) Integer sinceDays) {
        return ApiBaseResponse.success(articleService.listHotArticles(limit, categoryId, tagId, sinceDays));
    }

    // 归档（公开）
    @GetMapping("/archives")
    public ApiBaseResponse<List<ArticleArchiveItemVO>> archives(@RequestParam(required = false) Integer limit) {
        return ApiBaseResponse.success(articleService.listArchives(limit));
    }

    // 归档分页（公开）
    @GetMapping("/archives/page")
    public ApiBaseResponse<PageResponse<ArticleArchiveItemVO>> pageArchives(@RequestParam Integer pageNo,
                                                                            @RequestParam Integer pageSize) {
        return ApiBaseResponse.success(articleService.pageArchives(pageNo, pageSize));
    }

    // 热门分页（公开）
    @GetMapping("/hot/page")
    public ApiBaseResponse<PageResponse<ArticleListItemVO>> pageHot(@RequestParam Integer pageNo,
                                                                    @RequestParam Integer pageSize,
                                                                    @RequestParam(required = false) Long categoryId,
                                                                    @RequestParam(required = false) Long tagId,
                                                                    @RequestParam(required = false) Integer sinceDays) {
        return ApiBaseResponse.success(articleService.pageHot(pageNo, pageSize, categoryId, tagId, sinceDays));
    }

    // 最近发布（公开）
    @GetMapping("/recent")
    public ApiBaseResponse<List<ArticleListItemVO>> recent(@RequestParam(required = false) Integer limit) {
        return ApiBaseResponse.success(articleService.listRecentPublished(limit));
    }

    // 管理端：创建文章（最小可用）
    @PostMapping
    @com.blog.blog.util.annotations.RequirePerm({"article:write"})
    public ApiBaseResponse<Map<String, Object>> create(@Validated @RequestBody com.blog.blog.dto.SaveArticleDTO dto) {
        Long authorId = currentUserId();
        Long id = articleService.createArticle(dto, authorId);
        java.util.Map<String, Object> resp = new java.util.HashMap<>();
        resp.put("id", id);
        return ApiBaseResponse.success(resp);
    }

    // 管理端：更新文章
    @org.springframework.web.bind.annotation.PutMapping("/{id}")
    @com.blog.blog.util.annotations.RequirePerm({"article:update"})
    public ApiBaseResponse<Boolean> update(@PathVariable Long id, @Validated @RequestBody com.blog.blog.dto.SaveArticleDTO dto) {
        return ApiBaseResponse.success(articleService.updateArticle(id, dto));
    }

    // 管理端：删除文章
    @org.springframework.web.bind.annotation.DeleteMapping("/{id}")
    @com.blog.blog.util.annotations.RequirePerm({"article:delete"})
    public ApiBaseResponse<Boolean> delete(@PathVariable Long id) {
        return ApiBaseResponse.success(articleService.deleteArticle(id));
    }

    private Long currentUserId() {
        // AdminAuthInterceptor 已在请求属性写入 X-User-Id
        try {
            jakarta.servlet.http.HttpServletRequest req = ((org.springframework.web.context.request.ServletRequestAttributes) org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes()).getRequest();
            Object v = req.getAttribute("X-User-Id");
            if (v instanceof Long) return (Long) v;
            if (v instanceof String) return Long.parseLong((String) v);
        } catch (Exception ignore) {}
        return null;
    }
}


